package top.xtcoder.jdcbase.base.common;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.bouncycastle.crypto.digests.SHA3Digest;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.docx4j.fonts.CJKToEnglish;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlCallback;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.lang.util.NutMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonIgnore;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONObject;
import top.xtcoder.jdcbase.base.anno.FunsSqlIngore;
import top.xtcoder.jdcbase.base.config.FileUploadConf;
import top.xtcoder.jdcbase.base.core.Resp;
import top.xtcoder.jdcbase.base.entity.BaseEntity;

/**
 * 一些静态的工具方法
 * 
 * @author 向涛
 */
public class Funs {
	private final static Logger log = LoggerFactory.getLogger(Funs.class);
	public static void main(String[] args) {
		System.out.println(int2chineseNum(14));
	}
	
	public static String dateAddDate(String d, int data) throws ParseException {
       Date date = DateUtil.parse(d).toJdkDate();
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.DAY_OF_MONTH, data);
		LocalDateTime ldt = LocalDateTimeUtil.of(c.getTime());
		return ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
	}
	
	public static String getSaLoginId(int type, String userid) {
		return type + "-" + userid;
	}
	
	public static String getLoginId() {
		String[] ids = StpUtil.getLoginIdAsString().split("-");
		log.info("getLoginId=" + Arrays.toString(ids));
		if(ids != null && ids.length >= 2) {
			return ids[1];
		}
		return "";
	}
	
	public static int getLoginType() {
		String[] ids = StpUtil.getLoginIdAsString().split("-");
		log.info("getLoginType=" + Arrays.toString(ids));
		if(ids != null && ids.length >= 1) {
			return Integer.parseInt(ids[0]);
		}
		return -1;
	}
	
	public static String fmDecimal(BigDecimal decimal) {
        System.out.println(decimal);
        BigDecimal setScale = decimal.setScale(2, BigDecimal.ROUND_DOWN);
        return setScale.toString();
	}
	
	/**
	 * 文件上传初始化
	 * @param fileUploadConf
	 * @param ymd
	 * @param fileSuffix
	 * @return { url: url, saveFilePath: saveFilePath }
	 * @throws Exception
	 */
	public static Map<String, String> uploadFileInit(FileUploadConf fileUploadConf,
			String fileSuffix) throws Exception {
		String dir = fileUploadConf.getSavePath();
		String ymd = Funs.getNowLocalDate();
		//检查目录写权限
		File fileBaseDir = new File(dir);
		if(!fileBaseDir.canWrite()){
			throw new Exception("上传目录没有写权限。");
		}
		File fileDir = new File(dir+File.separator+ymd);
		if(!fileDir.exists()) {
			fileDir.mkdirs();
			File f = new File(dir+File.separator+ymd+File.separator+"index.html");
			f.createNewFile();
		}
		
		String fileName = Funs.getFileNameBySm3() + fileSuffix;
		String saveFilePath = fileDir+File.separator+fileName;
		
		String url = fileUploadConf.getBaseUrl() + "/" + ymd + "/" + fileName;
		
		Map<String, String> map = new HashMap<>();
		map.put("saveFilePath", saveFilePath);
		map.put("url", url);
		return map;
	}
	
	public static String int2chineseNum(int src) {
		String s = NumberChineseFormatter.format(src, false);
		if(src >= 10 && src <= 19) {
			s = s.substring(1);
		}
		return s;
//        final String num[] = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
//        final String unit[] = {"", "十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千"};
//        String dst = "";
//        int count = 0;
//        while(src > 0) {
//            dst = (num[src % 10] + unit[count]) + dst;
//            src = src / 10;
//            count++;
//        }
//        return dst.replaceAll("零[千百十]", "零").replaceAll("零+万", "万")
//                .replaceAll("零+亿", "亿").replaceAll("亿万", "亿零")
//                .replaceAll("零+", "零").replaceAll("零$", "");
    }
	
	public static Integer executeDDL(Dao dao, String sqlStr) {
		Sql sql = Sqls.create(sqlStr);
		sql.setCallback(new SqlCallback() {
			@Override
			public Integer invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
				return 1;
			}
		});
		dao.execute(sql);
		return sql.getInt();
	}
	
	/**
	 * 获取下一个半点或者整点
	 * [d=13:12 return=13:30][d=13:42 return=14:00]
	 * @param d
	 * @return
	 * @throws ParseException
	 */
	public static Date getNextBZ(Date d) throws ParseException {
		int t = d.getMinutes();
		if(t < 30) {
			d.setMinutes(30);
		}else {
			d.setHours(d.getHours() + 1);
			d.setMinutes(0);
		}
		return d;
	}
	
	/**
	 * 获取时间s, e中间的半点或者整点
	 * @param d
	 * @return
	 * @throws ParseException
	 */
	public static List<Date> getSETimeBZ(Date s, Date e) throws ParseException {
		List<Date> dates = new LinkedList<Date>();
		if(s.getTime() >= e.getTime()) {
			return dates;
		}
		
		if(s.getMinutes() == 30 || s.getMinutes() == 0) {
			dates.add((Date)s.clone());
		}
		while(s.getTime() <= e.getTime()) {
			s = getNextBZ(s);
			if(s.getTime() <= e.getTime()) {
				dates.add((Date)s.clone());
			}
		}
		return dates;
	}
	
	/**
	 * 时间添+秒s
	 * @param d
	 * @param s
	 * @return
	 */
	public  static Date dateAddSecond(Date d, int s) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.add(Calendar.SECOND, s);
		return c.getTime();
	}
	/**
	 * 时间添+秒s
	 * @param d
	 * @param s
	 * @return
	 */
	public  static Date dateAddSecond(Date d, long s) {
		return dateAddSecond(d, (int)s);
	}
	/**
	 * 6342 s 6342 / 60= 105 6342 % 60= 42
	 * 105 / 60= 1 105%60=45 
	 * 1:45:42
	 * 根据日期秒计算多少小时多少分多少秒
	 * @param time
	 * @return 
	 */
	public static String surplusTimerCalc(long allSeconds) {
		long min = allSeconds / 60; long seconds = allSeconds % 60;
		long hource = min / 60; min = min % 60;
		StringBuffer sb = new StringBuffer();
		if(hource > 0) {
			sb.append(hource + "小时");
		}
		if(min > 0) {
			sb.append(min + "分钟");
		}
		sb.append(seconds + "秒");
		return sb.toString();
	}
	
	public static double rad(double d) {
		return d * Math.PI / 180.0;
	}

	/**
	 * 我国常用三个坐标系，WGS84,、北京54及西安80，而WGS84椭球的长半轴就为6378137.0，
	 */
	public static final double EARTH_RADIUS = 6378.137;
	
	/**
	 * 验证手机号
	 *
	 * @param phone
	 * @return
	 */
	public static boolean checkPhone(String phone) {
		Pattern P_CM_NUM;
		Matcher M_CM_NUM;
		String CM_NUM = "^1(3[0-9]|4[57]|5[0-9]|66|7[135678]|8[0-9]|9[89])[0-9]{8}$";
		P_CM_NUM = Pattern.compile(CM_NUM);
		M_CM_NUM = P_CM_NUM.matcher(phone);
		if (M_CM_NUM.matches()) {
			return true;
		}
		return false;
	}

	/**
	 * 中国国家商用密码杂凑算法SM3
	 * 
	 * @author 呐喊
	 * @param str
	 * @return
	 */
	public static String sm3(String str) {
		str = (str == null) ? "" : str;
		byte[] pmdata = string2byte(str);
		SM3Digest sm3 = new SM3Digest();
		sm3.update(pmdata, 0, pmdata.length);
		byte[] hash = new byte[sm3.getDigestSize()];
		sm3.doFinal(hash, 0);
		String rsSM3 = ByteUtils.toHexString(hash);
		return rsSM3;
	}

	/**
	 * 中国国家商用密码杂凑算法SM3 HMAC消息认证
	 * 
	 * @author 呐喊
	 * @param str
	 * @return
	 */
	public static String sm3_hmac(String key, String str) {
		key = (key == null) ? "" : key;
		str = (str == null) ? "" : str;
		KeyParameter kp = new KeyParameter(string2byte(key));
		byte[] pmdata = string2byte(str);
		SM3Digest sm3 = new SM3Digest();
		HMac hmac = new HMac(sm3);
		hmac.init(kp);
		hmac.update(pmdata, 0, pmdata.length);
		byte[] hash = new byte[hmac.getMacSize()];
		hmac.doFinal(hash, 0);
		String rsSM3 = ByteUtils.toHexString(hash);
		return rsSM3;
	}

	public static String sha3(String str) {
		if (str == null) {
			str = "";
		}
		byte[] pmdata = string2byte(str);
		SHA3Digest sha3 = new SHA3Digest();
		sha3.update(pmdata, 0, pmdata.length);
		byte[] hash = new byte[sha3.getDigestSize()];
		sha3.doFinal(hash, 0);
		String resultSha3 = ByteUtils.toHexString(hash);
		return resultSha3;
	}

	public static byte[] string2byte(String s) {
		byte[] pmdata = null;
		try {
			pmdata = s.getBytes("utf-8");
			return pmdata;
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return pmdata;
	}

	/**
	 * 密码加密
	 * 
	 * @param sourcePwd 原密码
	 * @param salt      加密盐
	 * @return
	 */
	public static String pwdEncry(String sourcePwd, String salt) {
		return sm3_hmac(salt, sourcePwd);
	}

	public static String getRandom(int length) {
		Random random = new Random();
		StringBuilder rs = new StringBuilder();
		for (int i = 0; i < length; i++) {
			rs.append(random.nextInt(10));
		}
		return rs.toString();
	}

	/**
	 * 生成15位数ID
	 * 
	 * @return
	 */
	public static String getId() {
		long millis = System.currentTimeMillis();
		Random random = new Random();
		int end2 = random.nextInt(99);
		String string = millis + String.format("%02d", end2);
		return string;
	}

	/**
	 * 过滤掉手机端输入的表情字符
	 * 
	 * @param source
	 * @return
	 */
	public static String filterEmoji(String source) {
		if (source == null) {
			return source;
		}
		Pattern emoji = Pattern.compile("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
				Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
		Matcher emojiMatcher = emoji.matcher(source);
		if (emojiMatcher.find()) {
			source = emojiMatcher.replaceAll("*");
			return source;
		}
		return source;
	}

	/**
	 * 自定义ID生成 eg: GZTT19023830022305342748
	 * 
	 * @return
	 */
	public static String genId() {
		return Times.format("yy", new Date()) + "0" + longuuid();
	}
	
	public static void writeResp(HttpServletResponse response, Resp resp) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Type", "application/json");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setStatus(HttpServletResponse.SC_OK);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = null;
        try {
        	writer= response.getWriter();
            writer.write(Json.toJson(resp));
            writer.flush();
        } catch (Exception ex) {
            ex.printStackTrace();
        }finally {
            if(writer!=null) {
                writer.close();
            }
        }
    }
	public static String[] split(String s, String token) {
        if (s == null)
            return null;
        if (token == null || s.length() == 0)
            return new String[] { s };
        int size = 0;
        String[] result = new String[4];
        while (s.length() > 0) {
            int index = s.indexOf(token);
            String splitOne = s;
            if (index > -1) {
                splitOne = s.substring(0, index);
                s = s.substring(index + token.length());
            } else {
                s = "";
            }
            if (size >= result.length) {
                String[] tmp = new String[result.length * 2];
                System.arraycopy(result, 0, tmp, 0, result.length);
                result = tmp;
            }
            if (splitOne.length() > 0) {
                result[size++] = splitOne;
            }
        }
        String[] tmp = result;
        result = new String[size];
        System.arraycopy(tmp, 0, result, 0, size);
        return result;
    }
	public static String UUID() {
		String s = java.util.UUID.randomUUID().toString();
		return s.replaceAll("-", "");
	}
	public static String UUID36() {
		String s = java.util.UUID.randomUUID().toString();
		return s;
	}
	public static String createAccount() {
		String account = Times.format("yy", new Date()) + "0" + longuuid();
		return account;
	}
	/**
	 * 获取时间：yyyy-MM-dd HH:mm:ss
	 * @return
	 */
	public static String now() {
		return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
	}
	/**
	 * 获取时间：yyyyMMddHHmmss
	 * @return
	 */
	public static String nowNumber() {
		return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
	}
	public static String getYMD() {
		return Times.format("yyyy-MM-dd", new Date());
	}
	
	/**
	 * 数字类型的UUID
	 * 
	 * @return
	 */
	public static long longuuid() {
		return PrimaryKeyCreater.generateShortUuid();
	}
	
	public static long longuuid(String uuid) {
		return PrimaryKeyCreater.generateShortUuid(uuid);
	}

	public static String encodePassword(String password, String salt) {
		return Lang.md5(Lang.md5(password) + salt);
	}
	
	public static Integer[] getLevelArr(String level) {
		String[] str = level.split("");
		Integer[] is = new Integer[str.length];
		for(int i = 0; i < str.length; i ++) {
			is[i] = Integer.parseInt(str[i]);
		}
		return is;
	}
	
	/*
	 * 中文转unicode编码
	 */
	public static String gbEncoding(final String gbString) {
		char[] utfBytes = gbString.toCharArray();
		String unicodeBytes = "";
		for (int i = 0; i < utfBytes.length; i++) {
			String hexB = Integer.toHexString(utfBytes[i]);
			if (hexB.length() <= 2) {
				hexB = "00" + hexB;
			}
			unicodeBytes = unicodeBytes + "\\u" + hexB;
		}
		return unicodeBytes;
	}

	/*
	 * unicode编码转中文
	 */
	public static String decodeUnicode(final String dataStr) {
		int start = 0;
		int end = 0;
		final StringBuffer buffer = new StringBuffer();
		while (start > -1) {
			end = dataStr.indexOf("\\u", start + 2);
			String charStr = "";
			if (end == -1) {
				charStr = dataStr.substring(start + 2, dataStr.length());
			} else {
				charStr = dataStr.substring(start + 2, end);
			}
			char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
			buffer.append(new Character(letter).toString());
			start = end;
		}
		return buffer.toString();
	}

	public final static String getNowFullTimeNum() {
		LocalDateTime ldt = LocalDateTime.now();
		return ldt.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
	}

	/**
	 * 获取多少分钟之后的时间
	 * 
	 * @param min 分钟
	 * @return
	 */
	public final static String getNowFullTimeByXAfter(int min) {
		if (min == 0) {
			min = 60;
		}
		long time = System.currentTimeMillis();
		time += min * 1000 * 60;
		DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		String rzDate = df.format(time);
		return rzDate;
	}

	public final static String getNowFullTime() {
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String rzDate = df.format(new Date());
		return rzDate;
	}

	public static long dec2Value(BigDecimal bd1) {
		BigDecimal bd2 = bd1.multiply(new BigDecimal(100));
		long total_fee = bd2.longValue();
		return total_fee;
	}

	/**
	 * 去除文本中的html
	 * 
	 * @param htmlStr
	 * @return
	 */
	public static String delHTMLTag(String htmlStr) {
		String regEx_script = "<script[^>]*?>[\\s\\S]*?<\\/script>"; // 定义script的正则表达式
		String regEx_style = "<style[^>]*?>[\\s\\S]*?<\\/style>"; // 定义style的正则表达式
		String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式
		Pattern p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE);
		Matcher m_script = p_script.matcher(htmlStr);
		htmlStr = m_script.replaceAll(""); // 过滤script标签
		Pattern p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE);
		Matcher m_style = p_style.matcher(htmlStr);
		htmlStr = m_style.replaceAll(""); // 过滤style标签
		Pattern p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE);
		Matcher m_html = p_html.matcher(htmlStr);
		htmlStr = m_html.replaceAll(""); // 过滤html标签
		return htmlStr.replaceAll("\\s*|\t|\r|\n", "").trim(); // 返回文本字符串
	}

	/**
	 * 在html中获取图片地址
	 * 
	 * @param html
	 * @return
	 */
	public static List<String> getImgByHtml(String html) {
		List<String> srcList = new ArrayList<String>(); // 用来存储获取到的图片地址
		Pattern p = Pattern.compile("<(img|IMG)(.*?)(>|></img>|/>)");// 匹配字符串中的img标签
		Matcher matcher = p.matcher(html);
		boolean hasPic = matcher.find();
		if (hasPic == true)// 判断是否含有图片
		{
			while (hasPic) // 如果含有图片，那么持续进行查找，直到匹配不到
			{
				String group = matcher.group(2);// 获取第二个分组的内容，也就是 (.*?)匹配到的
				Pattern srcText = Pattern.compile("(src|SRC)=(\"|\')(.*?)(\"|\')");// 匹配图片的地址
				Matcher matcher2 = srcText.matcher(group);
				if (matcher2.find()) {
					srcList.add(matcher2.group(3));// 把获取到的图片地址添加到列表中
				}
				hasPic = matcher.find();// 判断是否还有img标签
			}

		}
		return srcList;
	}

	/**
	 * 将size B转换为KB, MB等等
	 * 
	 * @param size
	 * @return
	 */
	public static String getPrintSize(long size) {
		// 如果字节数少于1024，则直接以B为单位，否则先除于1024，后3位因太少无意义
		if (size < 1024) {
			return String.valueOf(size) + " B";
		} else {
			size = size / 1024;
		}
		// 如果原字节数除于1024之后，少于1024，则可以直接以KB作为单位
		// 因为还没有到达要使用另一个单位的时候
		// 接下去以此类推
		if (size < 1024) {
			return String.valueOf(size) + " KB";
		} else {
			size = size / 1024;
		}
		if (size < 1024) {
			// 因为如果以MB为单位的话，要保留最后1位小数，
			// 因此，把此数乘以100之后再取余
			size = size * 100;
			return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + " MB";
		} else {
			// 否则如果要以GB为单位的，先除于1024再作同样的处理
			size = size * 100 / 1024;
			return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + " GB";
		}
	}

	public static String getText(String text, String regex) {
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(text);
		if (matcher.find())
			return matcher.group(1);
		return null;
	}

	public static int string2int(String s) {
		if (s == null)
			return 0;
		s = getText(s, "(\\d+)");
		if ("".equals(s) || s == null)
			return 0;
		return Integer.parseInt(s);
	}

	public static Long string2Long(String s) {
		if (s == null)
			return 0l;
		s = getText(s, "(\\d+)");
		if ("".equals(s) || s == null)
			return 0l;
		return Long.parseLong(s);
	}
	
	public static Long obj2Long(Object obj) {
		if (obj == null) {return 0l;}
		String s = obj.toString();
		s = getText(s, "(\\d+)");
		if ("".equals(s) || s == null)
			return 0l;
		try {
			return Long.parseLong(s);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			System.out.println("error="+e.getMessage());
			return 0l;
		}
	}

	public static int obj2int(Object obj) {
		if (obj == null)
			return 0;
		try {
			String s = obj.toString();
			s = getText(s, "(\\d+)");
			if ("".equals(s) || s == null) {
				return 0;
			}
			return Integer.parseInt(s);
		} catch (NumberFormatException e) {
			// e.printStackTrace();
			System.out.println("error=");
			return 0;
		}
	}
	/**
	 * 
	 * @param obj
	 * @param defaultVal 为空的是默认返回值
	 * @return
	 */
	public static int obj2int(Object obj,int defaultVal) {
		if (obj == null)
			return defaultVal;
		try {
			String s = obj.toString();
			s = getText(s, "(\\d+)");
			if ("".equals(s) || s == null) {
				return defaultVal;
			}
			return Integer.parseInt(s);
		} catch (NumberFormatException e) {
			// e.printStackTrace();
			System.out.println("error=");
			return defaultVal;
		}
	}

	public final static String getNowDate4yyyyMM() {
		DateFormat df = new SimpleDateFormat("yyyyMM");
		String rzDate = df.format(new Date());
		return rzDate;
	}
	
	public static boolean isIPv4Address(final String input) {
		 Pattern IPv4Pattern = Pattern.compile("^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
        return IPv4Pattern.matcher(input).matches();
    }

    public static boolean isIPv6StdAddress(final String input) {
    	Pattern IPv6StdPattern = Pattern.compile("^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$");
        return IPv6StdPattern.matcher(input).matches();
    }

    public static boolean isIPv6HexCompressedAddress(final String input) {
    		Pattern IPV6HexCompressedPattrern = Pattern.compile("^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$");
        return IPV6HexCompressedPattrern.matcher(input).matches();
    }

    public static boolean isIPv6Address(final String input) {
        return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
    }
	
	/**
     * 获得访问者的IP地址, 反向代理过的也可以获得
     *
     * @param request
     *            请求的req对象
     * @return 来源ip
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (request == null)
            return "0.0.0.0";
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("X-Real-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
                if (ip.equals("127.0.0.1") || ip.equals("0:0:0:0:0:0:0:1")) {
	    				// 根据网卡取本机配置的IP
	    				InetAddress inet = null;
	    				try {
	    					inet = InetAddress.getLocalHost();
	    				} catch (UnknownHostException e) {
	    					e.printStackTrace();
	    				}
	    				ip = inet.getHostAddress();
    				}
            }
        } else if (ip.length() > 15) {
            String[] ips = ip.split(",");
            for (int index = 0; index < ips.length; index++) {
                String strIp = ips[index];
                if (!("unknown".equalsIgnoreCase(strIp))) {
                    ip = strIp;
                    break;
                }
            }
        }
        if (Strings.isBlank(ip))
            return "0.0.0.0";
        if (isIPv4Address(ip) || isIPv6Address(ip)) {
            return ip;
        }
        return "0.0.0.0";
    }
	
	/**
	 * 
	 * @param real_ip
	 * @return
	 */
	public static Map<String, Object> getIpInfo(String real_ip){
		Map<String, Object> map = new HashMap<String, Object>();
		HttpURLConnection connection ;
        String api = "http://ip.taobao.com/service/getIpInfo.php";
        String connect_symbol = "?";
        String front_name = "ip=";
        URL url ;
        BufferedReader bf ;
        StringBuffer sb = new StringBuffer();
        try {
            url = new URL(api+connect_symbol+front_name+real_ip);
            connection = (HttpURLConnection)url.openConnection();
            bf = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));
            String line = "";
            while(null!=(line = bf.readLine())){
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        JSONObject dataObject = new JSONObject(sb.toString());
        JSONObject jsonObject= dataObject.getJSONObject("data");
        map.put("region", jsonObject.get("region"));//省
        map.put("city", jsonObject.get("city")); //省会
        map.put("area", jsonObject.get("area")); //地级市
        return map;
//        System.out.println(jsonObject.toString());
//        System.out.println("ip:"+jsonObject.get("ip"));
//        System.out.println("country:"+jsonObject.get("country"));
//        System.out.println("area:"+jsonObject.get("area"));
//        System.out.println("region:"+jsonObject.get("region"));
//        System.out.println("county:"+jsonObject.get("county"));
//        System.out.println("isp:"+jsonObject.get("isp"));
//        System.out.println("city:"+jsonObject.get("city"));
//        System.out.println("country_id:"+jsonObject.get("country_id"));
//        System.out.println("area_id:"+jsonObject.get("area_id"));
//        System.out.println("region_id:"+jsonObject.get("region_id"));
//        System.out.println("city_id:"+jsonObject.get("city_id"));
//        System.out.println("county_id:"+jsonObject.get("county_id"));
//        System.out.println("isp_id:"+jsonObject.get("isp_id"));
	}
	/**
	 * 生成文件名，用时间年月日时分秒
	 * @return
	 */
	public final static String getFileNameByFullTime() {
		DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String rzDate = df.format(new Date());
		return rzDate + "_" + new Random().nextInt(10000);
	}
	
	public final static String getFileContentType(String filePath) {
		try  {
			Path path = new File(filePath).toPath();
			String contentType = java.nio.file.Files.probeContentType(path);
			return contentType;
		}catch(Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 获取文件的类型
	 * @param filePath
	 * @return
	 */
	public final static String getFileType(String filePath) {
		try  {
			Path path = new File(filePath).toPath();
			String contentType = java.nio.file.Files.probeContentType(path);
			return contentType.split("/")[1];
		}catch(Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 获取文件的后缀
	 * @param filePath
	 * @return
	 */
	public final static String getFileSuffix(String filePath) {
		return "." + getFileType(filePath);
	}
	
	/**
	 * 生成文件名,sm3加密（时间戳和UUID）生成
	 * @return
	 */
	public final static String getFileNameBySm3() {
		String fileName = Funs.sm3(new Date().getTime() + new Random().nextInt(10000) + Funs.UUID());
		return fileName;
	}
	
	public static double similarity(ArrayList va, ArrayList vb) {
        if (va.size() > vb.size()) {
            int temp = va.size() - vb.size();
            for (int i = 0; i < temp; i++) {
                vb.add(0);
            }
        } else if (va.size() < vb.size()) {
            int temp = vb.size() - va.size();
            for (int i = 0; i < temp; i++) {
                va.add(0);
            }
        }
 
        int size = va.size();
        double simVal = 0;
 
 
        double num = 0;
        double den = 1;
        double powa_sum = 0;
        double powb_sum = 0;
        for (int i = 0; i < size; i++) {
            double a = Double.parseDouble(va.get(i).toString());
            double b = Double.parseDouble(vb.get(i).toString());
 
            num = num + a * b;
            powa_sum = powa_sum + (double) Math.pow(a, 2);
            powb_sum = powb_sum + (double) Math.pow(b, 2);
        }
        double sqrta = (double) Math.sqrt(powa_sum);
        double sqrtb = (double) Math.sqrt(powb_sum);
        den = sqrta * sqrtb;
 
        simVal = num / den;
 
        return simVal;
    }
	
	public final static String getNowDate4yyyyMMDD() {
		LocalDate ld = LocalDate.now();
		return ld.format(DateTimeFormatter.BASIC_ISO_DATE);
	}
	/**
	 * 判断BigDecimal类型是否为空或者0
	 * @param bd
	 * @return 为null或者0返回true,否则返回false
	 */
	public static boolean BigDecimalIsEmpty(BigDecimal bd) {
		if(bd==null) {return true;}
		if(bd.compareTo(BigDecimal.ZERO)==0) {return true;}
		return false;
	}
	public static boolean BigDecimalIsNotEmpty(BigDecimal bd) {
		return !BigDecimalIsEmpty(bd);
	}
	/**
	 * 设置下载文件的Header信息
	 * @param request
	 * @param response
	 * @param fileName 文件名
	 * @return
	 */
	public static boolean setDownloadHeader(HttpServletRequest request, HttpServletResponse response, String fileName) {
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("content-type", "application/octet-stream");
            String browser = request.getHeader("User-Agent");
            if (-1 < browser.indexOf("MSIE 6.0") || -1 < browser.indexOf("MSIE 7.0")) {
                // IE6, IE7 浏览器
                response.addHeader("content-disposition", "attachment;filename="
                        + new String(fileName.getBytes(), "ISO8859-1"));
            } else if (-1 < browser.indexOf("MSIE 8.0")) {
                // IE8
                response.addHeader("content-disposition", "attachment;filename="
                        + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("MSIE 9.0")) {
                // IE9
                response.addHeader("content-disposition", "attachment;filename="
                        + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("Chrome")) {
                // 谷歌
                response.addHeader("content-disposition",
                        "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
            } else if (-1 < browser.indexOf("Safari")) {
                // 苹果
                response.addHeader("content-disposition", "attachment;filename="
                        + new String(fileName.getBytes(), "ISO8859-1"));
            } else {
                // 火狐或者其他的浏览器
                response.addHeader("content-disposition",
                        "attachment;filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
            }
            return true;
        } catch (Exception e) {
            //log.error(e.getMessage());
            return false;
        }
    }
	
	/**
	 * 求职状态
	 * @param state
	 * @return
	 */
	public static  String getJobState(int state) {
		String js="";
		switch (state) {
		case 1:
			js = "离职";
			break;
		case 2:
			js = "在职，可一个月到岗";
			break;
		case 3:
			js = "在职，考虑换工作";
			break;
		case 4:
			js = "在职，应届毕业生";
			break;
		default:
			break;
		}
		return js;
	}
	
	public static String getSalary(long min,long max) {
		if(min==-1 && max==-1) {
			return "面议";
		}
		if(min==-1) {
			String maxsalary = max+"";
			if(max>1000) {maxsalary = max/1000 + "K";}
			return maxsalary+"以下";
		}
		if(max==-1) {
			String minsalary = min+"";
			if(min>1000) {minsalary = min/1000 + "K";}
			return minsalary+"以上";
		}
		String minsalary = min+"";
		String maxsalary = max+"";
		if(max>1000) {maxsalary = max/1000 + "K";}
		if(min>1000) {minsalary = min/1000 + "K";}
		return minsalary+"-"+maxsalary;
	}
	
	public static String getWorkExpSalary(BigDecimal min,BigDecimal max) {
		if(min==null) {
			min = new BigDecimal("0");
		}
		if(max==null) {
			max = new BigDecimal("0");
		}
		if(min.compareTo(new BigDecimal("-1")) == 0) {
			String maxsalary = max+"";
			if(max.compareTo(new BigDecimal("1000"))==1) {maxsalary = max.divide(new BigDecimal("1000"),0,BigDecimal.ROUND_HALF_UP) + "K";}
			return maxsalary+"以下";
		}
		if(max.compareTo(new BigDecimal("-1")) == 0) {
			String minsalary = min+"";
			if(min.compareTo(new BigDecimal("1000"))==1) {minsalary = min.divide(new BigDecimal("1000"),0,BigDecimal.ROUND_HALF_UP) + "K";}
			return minsalary+"以上";
		}
		String minsalary = min+"";
		String maxsalary = max+"";
		if(max.compareTo(new BigDecimal("1000"))==1) {maxsalary = max.divide(new BigDecimal("1000"),0,BigDecimal.ROUND_HALF_UP) + "K";}
		if(min.compareTo(new BigDecimal("1000"))==1) {minsalary = min.divide(new BigDecimal("1000"),0,BigDecimal.ROUND_HALF_UP) + "K";}
		return minsalary+"-"+maxsalary;
	}
	/**
	 * 获取学历
	 * @param edu
	 * @return
	 */
	public static String getEducation(int edu) {
		String edutxt = "无";
		if(edu==0) {return "无";}
		String[] eduarr = {"无","小学","中学","初中","高中","专科","中专","大专","本科","硕士","博士","博士后"};
		String[] edumode = {"","以下","以上"};
		int a = edu%10;//对10取余，可得到个位数
		int b = edu/10;//除10得到十位数，由于b为整形，小数位会自动省略
		edutxt = eduarr[b]+edumode[a];
		return edutxt;
	}
	
	/**
	 * 判断c的数据是否全在p中
	 * @param c
	 * @param p
	 * @return 返回不在的数据, 空表示都在
	 */
	public static String cHasInP(List<String> c, List<String> p) {
		StringBuffer sb = new StringBuffer();
		for(int i = 0; i < c.size(); i ++) {
			boolean find = false;
			for(int j = 0; j < p.size(); j ++) {
				if(Strings.equals(c.get(i), p.get(j))) {
					find = true;
					break;
				}
			}
			if(!find) {
				sb.append(c.get(i) + " ");
			}
		}
		return sb.toString();
	}
	
	/**
	 * 判断实体类中每个属性是否都为空
	 * @param o
	 * @return
	 */
	public static boolean allFieldIsNULL(Object o){
		if(o==null) {return true;}
		try {
			for (Field field : o.getClass().getDeclaredFields()) {
				field.setAccessible(true);
				Object value = field.get(o);
				if (value instanceof CharSequence) {
					if (!org.springframework.util.ObjectUtils.isEmpty(value)) {
						return false;
					}
				} else {
					if (null != value) {
						return false;
					}
				}
			}
		} catch (Exception e) {
			System.out.println("判断对象属性为空异常" + e);
		}
		return true;
	}
	/**
	 * 将实体类中为空字符串的属性设为null
	 * @param obj
	 * @return 处理后的对象
	 */
	public static <T> T setFieldIsEmptyToNull(T obj){
		if(obj==null) {return obj;}
		try {
			for (Field field : obj.getClass().getDeclaredFields()) {
				field.setAccessible(true);
				Object value = field.get(obj);
				if (value instanceof CharSequence) {
					if (org.springframework.util.ObjectUtils.isEmpty(value)) {
						field.set(obj, null);
					}
				}
			}
			return obj;
		} catch (Exception e) {
			System.out.println("判断对象属性为空异常" + e);
			return obj;
		}
		
	}
	
	/**
	 * 将实体对象的属性转为mysql查询语句的select 和from中的字段
	 * prex.user_name as fieldPrexuserName
	 * @param cls 实体class
	 * @param prex 数据字段前缀
	 * @param fieldPrex 字段前缀
	 * @return
	 */
	public static String vo2mysqlField(Class<?> cls
			, String prex
			, String fieldPrex) {
		List<Field> fs = new ArrayList<>();
		Field[] cfs = cls.getDeclaredFields();
		fs.addAll(Arrays.asList(cfs));
		Field[] pfs = {};
		if(cls.getSuperclass().getName() == BaseEntity.class.getName()) {
			pfs = cls.getSuperclass().getDeclaredFields();
		}
		fs.addAll(Arrays.asList(pfs));
		if(fs.size() <= 0) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		int index = 0;
		for(int i = 0; i < fs.size(); i ++) {
			JsonIgnore jsonIgnore = fs.get(i).getAnnotation(JsonIgnore.class);
			if(jsonIgnore != null) {
				continue;
			}
			Column cd = fs.get(i).getDeclaredAnnotation(Column.class);
			if(cd != null) {
				if(Strings.isNotBlank(cd.value())) {
					if(index > 0) {
						sb.append(",");
					}
					sb.append(prex + "." + cd.value() + " as " + fieldPrex + fs.get(i).getName());
					index ++;
				}
			}
		}
		return sb.toString();
	}
	/**
	 * 将实体对象的属性转为Pgsql查询语句的select 和from中的字段
	 * prex.user_name as fieldPrexuserName
	 * @param cls 实体class
	 * @param prex 表名或表的别名
	 * @param fieldPrex 字段前缀
	 * @param isExtends 是否有继承
	 * @return
	 */
	public static String vo2PgsqlField(Class<?> cls
			, String prex
			, String fieldPrex,boolean isExtends) {
		prex = Funs.isBlank(prex)?"":prex+".";
		fieldPrex = Funs.isBlank(fieldPrex)?"":fieldPrex;
		
		List<Field> fs = new ArrayList<>();
		if(isExtends) {
			do {
				Field[] pfs = cls.getDeclaredFields();
				fs.addAll(Arrays.asList(pfs));
					cls = cls.getSuperclass();
			}while(!Strings.equals(cls.getName(), Object.class.getName()));
		}else {
			Field[] pfs = cls.getDeclaredFields();
			fs.addAll(Arrays.asList(pfs));
		}
		if(fs.size() <= 0) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		int index = 0;
		for(int i = 0; i < fs.size(); i ++) {
			JsonIgnore jsonIgnore = fs.get(i).getAnnotation(JsonIgnore.class);
			if(jsonIgnore != null) {
				continue;
			}
			FunsSqlIngore fsi = fs.get(i).getAnnotation(FunsSqlIngore.class);
			if(fsi != null) {
				continue;
			}
			Column cd = fs.get(i).getDeclaredAnnotation(Column.class);
			String fieldType = fs.get(i).getType().toString();
			if(cd != null) {
				if(Funs.isNotBlank(cd.value())) {
					if(index > 0) {
						sb.append(",");
					}
					if(fieldType.endsWith("Date")) {
						sb.append("to_char("+prex+cd.value()+",'yyyy-MM-DD HH24:MI:SS') as " + fieldPrex + fs.get(i).getName());
					}else {
						sb.append(prex+cd.value() + " as \"" + fieldPrex + fs.get(i).getName()+"\"");
					}
					index ++;
				}
			}
		}
		System.out.println("SB2=" + sb.toString());
		return sb.toString();
	}
	
	
	/**
	 * 将实体对象的属性转为Pgsql查询语句的select 和from中的字段
	 * prex.user_name as fieldPrexuserName
	 * @param cls 实体class
	 * @param alias 表的别名或表名
	 * @param fieldPrex 字段前缀
	 * @param filterField 需要过滤的字段，格式为pojo实体名,多个用竖线|分隔，如：userName|userPasswd
	 * @param allowField 只允许的字段，格式为pojo实体名,多个用竖线|分隔，如：userName|userPasswd
	 * @param isExtends 是否存在继承的类
	 * @return
	 */
	public static String vo2PgsqlField(Class<?> cls
			, String alias
			, String fieldPrex
			, String filterField
			, String allowField
			,boolean isExtends) {
		return vo2PgsqlField(cls, alias, fieldPrex, filterField, allowField, isExtends, true);
	}

	/**
	 * 将实体对象的属性转为Pgsql查询语句的select 和from中的字段
	 * prex.user_name as fieldPrexuserName
	 * @param cls 实体class
	 * @param alias 表的别名或表名
	 * @param fieldPrex 字段前缀
	 * @param filterField 需要过滤的字段，格式为pojo实体名,多个用竖线|分隔，如：userName|userPasswd
	 * @param allowField 只允许的字段，格式为pojo实体名,多个用竖线|分隔，如：userName|userPasswd
	 * @param isExtends 是否存在继承的类
	 * @param toEntityField 是否转为实体字段
	 * @return
	 */
	public static String vo2PgsqlField(Class<?> cls
			, String alias
			, String fieldPrex
			, String filterField
			, String allowField
			, boolean isExtends
			, boolean toEntityField) {
		alias = Funs.isBlank(alias) ? "" : alias+".";
		fieldPrex = Funs.isBlank(fieldPrex)?"":fieldPrex;
		List<Field> fs = new ArrayList<>();
		
		if(isExtends) {
			do {
				Field[] dfs = cls.getDeclaredFields();
				fs.addAll(Arrays.asList(dfs));
					cls = cls.getSuperclass();
			}while(!equals(cls.getName(), Object.class.getName()));
		}else {
			Field[] dfs = cls.getDeclaredFields();
			fs.addAll(Arrays.asList(dfs));
		}
		
		if(fs.size() <= 0) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		int index = 0;
		for(int i = 0; i < fs.size(); i ++) {
			JsonIgnore jsonIgnore = fs.get(i).getAnnotation(JsonIgnore.class);
			if(jsonIgnore != null) {
				continue;
			}
			if(Funs.isNotBlank(filterField)) {
				String[] filterFields = filterField.split("\\|");
				if(Arrays.asList(filterFields).contains(fs.get(i).getName())) {
					continue;
				}
			}
			if(Funs.isNotBlank(allowField)) {
				String[] allowFields = allowField.split("\\|");
				if(!Arrays.asList(allowFields).contains(fs.get(i).getName())) {
					continue;
				}
			}
			FunsSqlIngore fsi = fs.get(i).getAnnotation(FunsSqlIngore.class);
			if(fsi != null) {
				continue;
			}
			Column cd = fs.get(i).getDeclaredAnnotation(Column.class);
			String fieldType = fs.get(i).getType().toString();
			if(cd != null) {
				if(Funs.isNotBlank(cd.value())) {
					if(index > 0) {
						sb.append(",");
					}
					String columns = toEntityField ? fieldPrex + fs.get(i).getName()
							: fieldPrex + cd.value();
					if(fieldType.endsWith("Date")) {
						sb.append("to_char("+alias+cd.value()+",'yyyy-MM-DD HH24:MI:SS') as " + columns);
					}else {
						sb.append(alias+cd.value() + " as \"" + columns +"\"");
					}
					index ++;
				}
			}
		}
		System.out.println("SB: " + sb.toString());
		return sb.toString();
	}
	
	/**
	 * map转obj
	 * @param <T>
	 * @param cls
	 * @param map
	 * @return
	 */
	public <T> T map2obj(Class<T> cls, NutMap map){
		T object = null;
		try {
			object = cls.newInstance();
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		//检查是否空值
		if(map == null || map.isEmpty()){
			return null;
		}
		//获取Object属性数组
		Field[] fields = object.getClass().getDeclaredFields();
		//遍历数组
		for(Field field : fields){
			if(!field.isAccessible()){
				field.setAccessible(true);
			}
			//赋值
			try {
				String type = field.getType().getSimpleName();
				if("int".equals(type)) {
					field.setInt(object, map.getInt(field.getName()));
				}else if("double".equals(type)){
					field.setDouble(object, map.getDouble(field.getName()));
				}else if("float".equals(type)){
					field.setFloat(object, map.getFloat(field.getName()));
				}else {
					field.set(object, map.get(field.getName()));
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out.println("map->obj:" + e.getMessage());
			}
		}
		return object;
	}
	
	public static String firstUpperCase(String s) {
		if(Strings.isBlank(s)) {
			return s;
		}
 		return s.substring(0, 1).toUpperCase() + s.substring(1);
	}
	
	/**
	 * 将list转为map
	 * list=[{age:1, name:'n1', addr:"a1"}, {age:2,name:"n2", addr:"a3"}] key=name
	 * 返回的map={
	 * 	n1: {age:1, name:'n1', addr:"a1"},
	 *  n2: {age:2,name:"n2", addr:"a3"}
	 * }
	 * @param <T>
	 * @param list 需要转为Map的list
	 * @param key 作为map的key值，为list中item的其中一个字段的值
	 * 			，不能是数字字段，必须为字符串且不重复
	 * @return
	 */
	public static <T> Map list2map(List<T> list, String key) {
		if(list == null || list.size() <= 0 || Strings.isBlank(key)) {
			System.out.println("Funs.list2map -> 所传参数为空");
			return null;
		}
		T t = list.get(0);
		try {
			Field field = t.getClass().getDeclaredField(key);
			if(field == null) {
				System.out.println("Funs.list2map -> 所传key不是list项中的字段");
				return null;
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		Map<String, T> map = new HashMap<>();
		for(T item:list) {
			try {
				Field field = t.getClass().getDeclaredField(key);
				field.setAccessible(true);
				Method me = item.getClass().getMethod("get" + Strings.upperFirst(key));
				map.put((String)me.invoke(item), item);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return map;
	}
	
	public static Date timeParse(String time) {
    	if(Strings.isBlank(time)) {
    		return null;
    	}
    	time = time.replaceAll("/", "-").trim();
    	ArrayList<SimpleDateFormat> dateFormats = new ArrayList<SimpleDateFormat>(); 
    	dateFormats.add(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"));
    	dateFormats.add(new SimpleDateFormat("yyyy年MM月dd日 HH:mm"));
        dateFormats.add(new SimpleDateFormat("yyyy年MM月dd日 HH"));
    	dateFormats.add(new SimpleDateFormat("yyyy年MM月dd日"));
    	dateFormats.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    	dateFormats.add(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
        dateFormats.add(new SimpleDateFormat("yyyy-MM-dd HH"));
        dateFormats.add(new SimpleDateFormat("yyyy-MM-dd"));
        
        for (SimpleDateFormat format : dateFormats){ 
        	try {
        		format.setLenient(false); 
        		Date date = format.parse(time); 
        		return date; 
        	} catch (Exception e) { 

        	} 
        }
    	System.out.println("时间["+time+"]解析不了了");
    	return null;
    }
	
	/**
	 * 字符串类型日期转换成Date类型
	 * @param date
	 * @return
	 */
	public static Date string2Date(String date) {
		try {
			String fmt = "yyyy-MM-dd";
			if(date.contains(".")) {
				fmt = "yyyy-MM-dd";
				date = date.replace(".", "-");
			}else if(date.contains("/")) {
				fmt = "yyyy/MM/dd";
			}else if(date.contains("-")) {
				fmt = "yyyy-MM-dd";
			}else {
				fmt = "yyyyMMdd";
			}
			SimpleDateFormat myFormatter = new SimpleDateFormat(fmt);
			java.util.Date mydate = myFormatter.parse(date);
			return mydate;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return new Date();
	}
	
	public static long getShijinacuo(String date) {
		return formatCan(date).getTime();
	}
	
	public static Date formatCan(String date) {
		String[] format = {
			"yyyy-MM-dd HH:mm:ss",
			"yyyy-MM-dd HH:mm",
			"yyyy-MM-dd HH",
			"yyyy-MM-dd",
			
			"yyyy/MM/dd HH:mm:ss",
			"yyyy/MM/dd HH:mm",
			"yyyy/MM/dd HH",
			"yyyy/MM/dd",
			
			"MM/dd HH:mm:ss",
			"MM/dd HH:mm",
			"MM/dd HH",
			"MM/dd",
			
			"MM-dd HH:mm:ss",
			"MM-dd HH:mm",
			"MM-dd HH",
			"MM-dd",
		};
		for(int i = 0; i < format.length; i ++) {
			try {
				Date d = Times.parse(format[i], date);
				return d;
			}catch(Exception e) {
				//System.out.println(date + "不是" + format[i] + "格式的数据");
			}
		}
		return new Date();
	}
	
	public static String getTableName(Class<?> cls) {
		Table table = cls.getAnnotation(Table.class);
		return table.prefix() + table.value() + table.suffix();
	}
	
	public static String getTableName(Class<?> cls, String alias) {
		Table table = cls.getAnnotation(Table.class);
		return table.prefix() + table.value() + table.suffix() + " " + alias;
	}
	
	/**
	 * 根据出生年月日获取年龄
	 * @param dateOfBirth
	 * @return
	 */
	public static int getAge(Date birthDay) {
        int age = 0;
        Calendar born = Calendar.getInstance();
        Calendar now = Calendar.getInstance();
        if (birthDay != null) {
            now.setTime(new Date());
            born.setTime(birthDay);
            if (born.after(now)) {
                throw new IllegalArgumentException("年龄不能超过当前日期");
            }
            age = now.get(Calendar.YEAR) - born.get(Calendar.YEAR);
            int nowDayOfYear = now.get(Calendar.DAY_OF_YEAR);
            int bornDayOfYear = born.get(Calendar.DAY_OF_YEAR);
            //System.out.println("nowDayOfYear:" + nowDayOfYear + " bornDayOfYear:" + bornDayOfYear);
            if (nowDayOfYear < bornDayOfYear) {
                age -= 1;
            }
        }
        return age;
    }
	/**
	 * 根据出生年月日获取年龄
	 * @param dateOfBirth
	 * @return
	 */
	public static int getAge(String birthDay) {
        int age = 0;
        Calendar born = Calendar.getInstance();
        Calendar now = Calendar.getInstance();
        if (Funs.isNotBlank(birthDay)) {
            now.setTime(new Date());
            born.setTime(Funs.string2Date(birthDay));
            if (born.after(now)) {
                throw new IllegalArgumentException("年龄不能超过当前日期");
            }
            age = now.get(Calendar.YEAR) - born.get(Calendar.YEAR);
            int nowDayOfYear = now.get(Calendar.DAY_OF_YEAR);
            int bornDayOfYear = born.get(Calendar.DAY_OF_YEAR);
            //System.out.println("nowDayOfYear:" + nowDayOfYear + " bornDayOfYear:" + bornDayOfYear);
            if (nowDayOfYear < bornDayOfYear) {
                age -= 1;
            }
        }
        return age;
    }
	
	/**
     * 如果此字符串为 null 或者全为空白字符(包含：空格、tab 键、换行符)，则返回 true
     *
     * @param cs
     *            字符串
     * @return 如果此字符串为 null 或者全为空白字符，则返回 true
     */
	public static boolean isBlank(CharSequence cs) {
        if (null == cs)
            return true;
        int length = cs.length();
        for (int i = 0; i < length; i++) {
            if (!(Character.isWhitespace(cs.charAt(i))))
                return false;
        }
        return true;
    }
	/**
     * 如果此字符串不为 null 或者全为空白字符(包含：空格、tab 键、换行符)，则返回 true
     *
     * @param cs
     *            字符串
     * @return 如果此字符串不为 null 或者全为空白字符，则返回 true
     */
    public static boolean isNotBlank(CharSequence cs) {
        return !isBlank(cs);
    }
    /**
     * 检查两个字符串是否相等.
     *
     * @param s1
     *            字符串A
     * @param s2
     *            字符串B
     * @return true 如果两个字符串相等,且两个字符串均不为null
     */
    public static boolean equals(String s1, String s2) {
        return s1 == null ? s2 == null : s1.equals(s2);
    }
    
    public static long minTime() {
    	return Times.parseq("yyyy-MM-dd", "1994-01-11").getTime();
    }
    
    public static long maxTime() {
    	return Times.parseq("yyyy-MM-dd", "3021-01-11").getTime();
    }
    
    /**
     * 检测URL地址是否能正常连接
     * @param url 需要测试的URL地址
     * @return 能正常连接返回true，否则返回false
     */
    public static boolean testURLConn(String url){
		int status = 404;
		try {
			URL conn = new URL(url);
			HttpURLConnection openConn = (HttpURLConnection) conn.openConnection();
			openConn.setUseCaches(false);
			openConn.setConnectTimeout(3000); //设置超时时间
		   status = openConn.getResponseCode();//获取请求状态
		   if (200 == status) {
		    return true;
		   }
		} catch (Exception e) {
		   //e.printStackTrace();
			System.out.println(e.getMessage());
		}
		return false;
	}
    /**  
     * 计算两个日期之间相差的天数  
     * @param smdate 较小的日期 
     * @param bdate  较大的日期 
     * @return 相差天数 
     * @throws ParseException  
     */  
    public static int daysBetween(Date smdate,Date bdate) throws ParseException    
    {    
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd");  
        smdate=sdf.parse(sdf.format(smdate));  
        bdate=sdf.parse(sdf.format(bdate));  
        Calendar cal = Calendar.getInstance();    
        cal.setTime(smdate);    
        long time1 = cal.getTimeInMillis();                 
        cal.setTime(bdate);    
        long time2 = cal.getTimeInMillis();         
        long between_days=(time2-time1)/(1000*3600*24);  
            
       return Integer.parseInt(String.valueOf(between_days));           
    }    
    /**
     * 字符串的日期格式的计算 两个日期之间相差的天数
     * @param smdate 较小的日期
     * @param bdate 较大的日期
     * @return 相差天数
     */
    public static int daysBetween(String smdate,String bdate){  
    	 try {
			Calendar cal = Calendar.getInstance();    
		   cal.setTime(string2Date(smdate));    
		   long time1 = cal.getTimeInMillis();                 
		   cal.setTime(string2Date(bdate));    
		   long time2 = cal.getTimeInMillis();         
		   long between_days=(time2-time1)/(1000*3600*24);  
		        
		   return Integer.parseInt(String.valueOf(between_days));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
       return 0;
    }
    
    /**
     * 计算2个日期之间相差多少年月日
     * 比如：2017-07-01 到  2020-04-17 相差 2年，9个月，21天
     * @author cy
     * @param fromDate 较小的日期
     * @param toDate 较大的日期
     * @return 如：2年9个月21天
     */
    public static String daysFormat(String fromDate,String toDate) {
    	toDate = equals(toDate, "-1")?getYMD():toDate;
		Calendar cal = Calendar.getInstance();    
	   cal.setTime(string2Date(fromDate));
	   long time1 = cal.getTimeInMillis();                 
	   cal.setTime(string2Date(toDate));    
	   long time2 = cal.getTimeInMillis();         
	   Long between_days = (time2-time1)/(1000*3600*24); 
    	int betweenDay = between_days.intValue();
    	
		int year,month,mod,day;
		StringBuffer result = new StringBuffer();
		if(betweenDay>365) {
			//得到年
			year = betweenDay/365;
			//得到计算年剩余的天数
			mod = betweenDay%365;
			result.append(year+"年");
			if(mod>30) {
				//得到月
				month = mod/30;
				//得到计算月剩余的天数
				day = mod%30;
				result.append(month+"个月");
				if(day>0) {
					result.append(day+"天");
				}
			}else {
				if(mod>0) {
					result.append(mod+"天");
				}
			}
		}else if(betweenDay>30) {
			//得到月
			month = betweenDay/30;
			//得到计算月剩余的天数
			day = betweenDay%30;
			result.append(month+"个月");
			if(day>0) {
				result.append(day+"天");
			}
		}else {
			if(betweenDay > 0) {
				result.append(betweenDay+"天");
			}
		}
		return result.toString();
    }
    /**
     * 计算2个日期之间相差多少年月日
     * 比如：2017-07-01 到  2020-04-17 相差 2年，9个月，21天
     * @author cy
     * @param fromDate 较小的日期
     * @param toDate 较大的日期
     * @param rsMonth 是否返回月数,true返回月（如2年9个月），否则不返回
     * @param rsDay 是否返回天数,true返回天（如2年9个月21天），否则不返回
     * @return
     */
    public static String daysFormat(String fromDate,String toDate,boolean rsMonth,boolean rsDay) {
		Calendar cal = Calendar.getInstance();    
	   cal.setTime(string2Date(fromDate));
	   long time1 = cal.getTimeInMillis();                 
	   cal.setTime(string2Date(toDate));    
	   long time2 = cal.getTimeInMillis();         
	   Long between_days = (time2-time1)/(1000*3600*24); 
    	int betweenDay = between_days.intValue();
    	
		int year,month,mod,day;
		StringBuffer result = new StringBuffer();
		if(betweenDay>365) {
			//得到年
			year = betweenDay/365;
			//得到计算年剩余的天数
			mod = betweenDay%365;
			result.append(year+"年");
			if(mod>30) {
				if(mod<=120) {
					//小于120天，按照一个月30天计算
					//得到月
					month = mod/30;
					//得到计算月剩余的天数
					day = mod%30;
					if(rsMonth) {
						result.append(month+"个月");
					}
					if(rsDay && day>0) {
						result.append(day+"天");
					}
				}else if(mod>120) {
					//大于120天，除去120天的剩余部分按照一个月31天计算
					int mods = mod-120;
					month = 4;
					//得到月
					month += mods/31;
					//得到计算月剩余的天数
					day = mods%31;
					if(rsMonth) {
						result.append(month+"个月");
					}
					if(rsDay && day>0) {
						result.append(day+"天");
					}
				}
			}else {
				if(rsDay && mod>0) {
					result.append(mod+"天");
				}
			}
		}else if(betweenDay>30) {
			//得到月
			month = betweenDay/30;
			//得到计算月剩余的天数
			day = betweenDay%30;
			if(rsMonth) {
				result.append(month+"个月");
			}
			if(rsDay && day>0) {
				result.append(day+"天");
			}
		}else {
			if(rsDay && betweenDay > 0) {
				result.append(betweenDay+"天");
			}
		}
		return result.toString();
    }
    /**
     * 判断时间是否满足某一类格式中某个格式
     * @param fmtArr 时间格式数组 eg:['YYYY-MM-dd', 'YYYY-MM-dd HH:mm']
     * @param date 判断的日期字符串
     * @return
     */
    public static boolean checkDateFormat(String[] fmtArr, String date) {
    	if(fmtArr == null || fmtArr.length <= 0) {
    		return false;
    	}
    	if(Strings.isBlank(date)) {
    		return false;
    	}
    	for(int i = 0; i < fmtArr.length; i ++) {
    		try {
    			Date d = Times.parse(fmtArr[i], date);
    			//解析成功
    			if(d != null) {
    				return true;
    			}
    		}catch(Exception e) {
    			//不满足，继续解析下一个
    		}
    	}
    	return false;
    }
    
    /**
     * 将天数格式化为多少年月日
     * 比如：1024天为： 2年9个月24天
     * @author cy
     * @param days 天数
     * @param rsMonth 是否返回月数,true返回月（如2年9个月），否则不返回
     * @param rsDay 是否返回天数,true返回天（如2年9个月24天），否则不返回
     * @return
     */
    public static String daysFormat(int days,boolean rsMonth,boolean rsDay) {
    	int betweenDay = days;
    	
		int year,month,mod,day;
		StringBuffer result = new StringBuffer();
		if(betweenDay>365) {
			//得到年
			year = betweenDay/365;
			//得到计算年剩余的天数
			mod = betweenDay%365;
			result.append(year+"年");
			if(mod>30) {
				if(mod<=120) {
					//小于120天，按照一个月30天计算
					//得到月
					month = mod/30;
					//得到计算月剩余的天数
					day = mod%30;
					if(rsMonth) {
						result.append(month+"个月");
					}
					if(rsDay && day>0) {
						result.append(day+"天");
					}
				}else if(mod>120) {
					//大于120天，除去120天的剩余部分按照一个月31天计算
					int mods = mod-120;
					month = 4;
					//得到月
					month += mods/31;
					//得到计算月剩余的天数
					day = mods%31;
					if(rsMonth) {
						result.append(month+"个月");
					}
					if(rsDay && day>0) {
						result.append(day+"天");
					}
				}
			}else {
				if(rsDay && mod>0) {
					result.append(mod+"天");
				}
			}
		}else if(betweenDay>30) {
			//得到月
			month = betweenDay/30;
			//得到计算月剩余的天数
			day = betweenDay%30;
			if(rsMonth) {
				result.append(month+"个月");
			}
			if(rsDay && day>0) {
				result.append(day+"天");
			}
		}else {
			if(rsDay && betweenDay > 0) {
				result.append(betweenDay+"天");
			}
		}
		return result.toString();
    }
    
    /**
     * 获取指定日期的月份的最后一天
     * @param yearMonth
     * @return
     */
    public static String getLastDayOfMonth(String yearMonth) {
    	yearMonth = yearMonth.replace(".", "-").replace("/", "-");
		int year = Integer.parseInt(yearMonth.split("-")[0]);  //年
		int month = Integer.parseInt(yearMonth.split("-")[1]); //月
		Calendar cal = Calendar.getInstance();
		// 设置年份
		cal.set(Calendar.YEAR, year);
		// 设置月份
		// cal.set(Calendar.MONTH, month - 1);//设置当前月的上一个月
		cal.set(Calendar.MONTH, month); 
		// 获取某月最大天数
		//int lastDay = cal.getActualMaximum(Calendar.DATE);
		int lastDay = cal.getMinimum(Calendar.DATE); //获取月份中的最小值，即第一天
		// 设置日历中月份的最大天数
		//cal.set(Calendar.DAY_OF_MONTH, lastDay);
		cal.set(Calendar.DAY_OF_MONTH, lastDay - 1); //上月的第一天减去1就是当月的最后一天
		// 格式化日期
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		return sdf.format(cal.getTime());
	}
    

	/**
     * 版本号比较
     *
     * @param v1
     * @param v2
     * @return 0代表相等，1代表左边大，-1代表右边大
     * Utils.compareVersion("1.0.358_20180820090554","1.0.358_20180820090553")=1
     */
    public static int compareVersion(String v1, String v2) {
    	 if(v1==null || v2==null || "".equals(v1) || "".equals(v2)) {return 0;}
        if (v1.equals(v2)) {return 0;}
        String[] version1Array = v1.split("[._]");
        String[] version2Array = v2.split("[._]");
        int index = 0;
        int minLen = Math.min(version1Array.length, version2Array.length);
        long diff = 0;
        while (index < minLen && (diff = Long.parseLong(version1Array[index])
                - Long.parseLong(version2Array[index])) == 0) {
            index++;
         }
        if (diff == 0) {
            for (int i = index; i < version1Array.length; i++) {
                if (Long.parseLong(version1Array[i]) > 0) {
                    return 1;
                }
            }
           for (int i = index; i < version2Array.length; i++) {
                if (Long.parseLong(version2Array[i]) > 0) {
                    return -1;
                }
            }
            return 0;
        } else {
            return diff > 0 ? 1 : -1;
        }
    }
  
    /**
	 * 获得最近几个月
	 * @param size
	 * @param asc
	 * @return
	 */
	public static List<String> getLastMonths(int size,boolean asc) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        List<String> list = new ArrayList<String>(size);
        for (int i=0;i<size;i++) {
            c.setTime(new Date());
            c.add(Calendar.MONTH, -i);
            Date m = c.getTime();
            list.add(sdf.format(m));
        }
       if(asc) {
        	Collections.reverse(list);
        }
        return list;

    }
	
	/**
	 * 获取当前日期，格式为：20111203
	 * @return
	 */
	public final static String getNowLocalDate() {
		LocalDate ld = LocalDate.now();
		return ld.format(DateTimeFormatter.BASIC_ISO_DATE);
	}
	/**
	 * 获取当前日期，格式为：2011-12-03
	 * @return
	 */
	public final static String getNowLocalIsoDate() {
		LocalDate ld = LocalDate.now();
		return ld.format(DateTimeFormatter.ISO_LOCAL_DATE);
	}
	/**
	 * 获取当前年，格式为：2021
	 * @return
	 */
	public final static int getNowLocalYear() {
		LocalDate ld = LocalDate.now();
		return ld.getYear();
	}
	/**
	 * 获取当前月份，格式为：1
	 * @return
	 */
	public final static int getNowLocalMonth() {
		LocalDate ld = LocalDate.now();
		return ld.getMonthValue();
	}
	/**
	 * 解析年级
	 * @param grade
	 * @return
	 */
	public static String parseGrade(int grade) {
		if(grade<=0 && grade>12) {
			return "";
		}
		String[] g = {"","一年级","二年级","三年级","四年级","五年级","六年级","七年级","八年级","九年级","高一","高二","高三"};
		return g[grade];
	}
	
    /**
     * 解析学期
     * @param semester
     * @return
     */
	public static String parseSemester(int semester) {
		if(semester<=0) {
			return "";
		}
		String[] s = {"","第一学期","第二学期","第三学期"};
		return s[semester];
	}
	/**
	 * 正则匹配
	 * <br>eg：Funs.matcher("01000","^[01]{1}1[01]{3}$")
	 * @param text
	 * @param regex
	 * @return
	 */
	public static boolean matcher(String text, String regex) {
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(text);
		return matcher.matches();
	}
	/**
	 * 格式化日期
	 * @param dateStr 日期字符串
	 * @param dtf DateTimeFormatter
	 * @return
	 */
	public static String parseDate(String dateStr,DateTimeFormatter dtf){
		try {
			if(dateStr==null || "".equals(dateStr)) {return "";}
			LocalDate date = LocalDate.parse(dateStr,dtf);
			return date.toString();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return "";
		}
	}
	/**
	 * 计算百分比：如成绩及格率等
	 * @param total 总数
	 * @param sub 需要计算的数
	 * @return
	 */
	public static String percentage(int total,int sub) {
		if(total==0) {
			return "0%";
		}
		BigDecimal bdtotal = new BigDecimal(total+"");
		BigDecimal bdsub = new BigDecimal(sub+"");
		BigDecimal div = bdsub.divide(bdtotal,4,BigDecimal.ROUND_HALF_UP);
		BigDecimal rs = div.multiply(new BigDecimal("100"));
		return rs.stripTrailingZeros().toPlainString()+"%";
	}
	
	/**
	 * 获取img标签中的src值
	 * @param content
	 * @return
	 */
	public static List<String> getImgSrc(String content){
	    List<String> list = new ArrayList<String>();
	    //目前img标签标示有3种表达式
	    //<img alt="" src="1.jpg"/>   <img alt="" src="1.jpg"></img>     <img alt="" src="1.jpg">
	    //开始匹配content中的<img />标签
	    Pattern p_img = Pattern.compile("<(img|IMG)(.*?)(/>|></img>|>)");
	    Matcher m_img = p_img.matcher(content);
	    boolean result_img = m_img.find();
	    if (result_img) {
	        while (result_img) {
	            //获取到匹配的<img />标签中的内容
	            String str_img = m_img.group(2);

	            //开始匹配<img />标签中的src
	            Pattern p_src = Pattern.compile("(src|SRC)=(\"|\')(.*?)(\"|\')");
	            Matcher m_src = p_src.matcher(str_img);
	            if (m_src.find()) {
	                String str_src = m_src.group(3);
	                list.add(str_src);
	            }
	            //结束匹配<img />标签中的src

	            //匹配content中是否存在下一个<img />标签，有则继续以上步骤匹配<img />标签中的src
	            result_img = m_img.find();
	        }
	    }
	    return list;
	}
	
	/**
	 * 过滤HTML里去除fs外的所有标签 比如fs=img|p|span 则过滤掉除img,p,span之外的标签（&nbsp;将特殊处理，替换为空格）
	 * @param str 处理的字符串
	 * @param fs 保留的标签 为空则保留所有
	 * @return
	 */
	public static String strHtmlFilter(String str, String fs) {
		if(Strings.isBlank(str)) {
			return str;
		}
		str = str.replaceAll("&nbsp;", " ");
		if(Strings.isBlank(fs)) {
			return str;
		}
		
		String regEx = "(?!<(" + fs + ").*?>)<.*?>";
		Pattern p_html = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
		Matcher m_html = p_html.matcher(str);
		str = m_html.replaceAll("");
		return str.trim(); // 返回文本字符串
	}
	
	/**
	 * 返回BigDecimal字符串
	 * @param bd
	 * @return
	 */
	public static String toPlainString(BigDecimal bd) {
		if(bd==null) {return "0";}
		return bd.stripTrailingZeros().toPlainString();
	}
	/**
	 * 返回BigDecimal字符串，带精度
	 * @param bd
	 * @param scale
	 * @return
	 */
	public static String toPlainString(BigDecimal bd,int scale) {
		if(bd==null) {return "0";}
		bd = bd.setScale(scale,BigDecimal.ROUND_HALF_UP);
		return bd.stripTrailingZeros().toPlainString();
	}
	/**
	 * 通过学校规模解析年级
	 * @param scale
	 * @return
	 */
	public static List<Integer> parseGradeScale(String scale) {
		List<Integer> gradeArr = new ArrayList<Integer>();
		switch (scale) {
		case "100":
			for(int i=1;i<=6;i++) {
				gradeArr.add(i);
			}
			break;
		case "110":
			for(int i=1;i<=9;i++) {
				gradeArr.add(i);
			}
			break;
		case "111":
			for(int i=1;i<=12;i++) {
				gradeArr.add(i);
			}
			break;
		case "010":
			for(int i=7;i<=9;i++) {
				gradeArr.add(i);
			}
			break;
		case "011":
			for(int i=7;i<=12;i++) {
				gradeArr.add(i);
			}
			break;
		case "001":
			for(int i=10;i<=12;i++) {
				gradeArr.add(i);
			}
			break;
		case "101":
			for(int i=1;i<=6;i++) {
				gradeArr.add(i);
			}
			for(int i=10;i<=12;i++) {
				gradeArr.add(i);
			}
			break;
		default:
			break;
		}
		return gradeArr;
	}
	/**
	 * 通过学校规模解析年级
	 * @param scale
	 * @return
	 */
	public static List<Map> parseGradeScaleToListMap(String scale) {
		List<Map> gradeArr = new ArrayList<Map>();
		getNowLocalDate();
		switch (scale) {
		case "100":
			for(int i=1;i<=6;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			break;
		case "110":
			for(int i=1;i<=9;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			break;
		case "111":
			for(int i=1;i<=12;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			break;
		case "010":
			for(int i=7;i<=9;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			break;
		case "011":
			for(int i=7;i<=12;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			break;
		case "001":
			for(int i=10;i<=12;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			break;
		case "101":
			for(int i=1;i<=6;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			for(int i=10;i<=12;i++) {
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(i));
				data.put("gradeValue", i);
				gradeArr.add(data);
			}
			break;
		default:
			break;
		}
		return gradeArr;
	}
	
	/**
	 * 通过学校规模解析年级
	 * @param scale
	 * @param semester 学期:1上学期，2下学期
	 * @return gradeType:1小学，2初中，3高中
	 */
	public static List<Map> parseGradeScaleToListMapV2(String scale,int semester) {
		List<Map> gradeArr = new ArrayList<Map>();
		int year = getNowLocalYear();
		int month = getNowLocalMonth();
		boolean secondSemester = false;
		if(semester ==1) {
			secondSemester = true;
		}else if(semester ==1) {
			secondSemester = false;
		}else {
			secondSemester = month>7;
		}
		int gradeYear = secondSemester?year:(year-1);
		switch (scale) {
		case "100":
			for(int i=gradeYear;i>(gradeYear - 6);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 1);
				gradeArr.add(data);
			}
			break;
		case "110":
			for(int i=gradeYear;i>(gradeYear - 6);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 1);
				gradeArr.add(data);
			}
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 6;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 2);
				gradeArr.add(data);
			}
			break;
		case "111":
			for(int i=gradeYear;i>(gradeYear - 6);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 1);
				gradeArr.add(data);
			}
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 6;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 2);
				gradeArr.add(data);
			}
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 9;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 3);
				gradeArr.add(data);
			}
			break;
		case "010":
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 6;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 2);
				gradeArr.add(data);
			}
			break;
		case "011":
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 6;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 2);
				gradeArr.add(data);
			}
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 9;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 3);
				gradeArr.add(data);
			}
			break;
		case "001":
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 9;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 3);
				gradeArr.add(data);
			}
			break;
		case "101":
			for(int i=gradeYear;i>(gradeYear - 6);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 1);
				gradeArr.add(data);
			}
			
			for(int i=gradeYear;i>(gradeYear - 3);i--) {
				int diff = year-i;
				diff = secondSemester?(diff+1):diff;
				diff = diff + 9;
				Map<String,Object> data =new HashMap<String,Object>();
				data.put("gradeName", parseGrade(diff));
				data.put("gradeValue", i);
				data.put("gradeType", 3);
				gradeArr.add(data);
			}
			break;
		default:
			break;
		}
		return gradeArr;
	}

	public static boolean isIdentityCode(String code) {
		int IDENTITYCODE_OLD = 15; // 老身份证15位
		int IDENTITYCODE_NEW = 18; // 新身份证18位
		int[] coeff = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
		char[] end = {'1','0','X','9','8','7','6','5','4','3','2'};

		if (Strings.isEmpty(code)) {
			return false;
		}

		String birthDay = "";
		code = code.trim().toUpperCase();

		// 长度只有15和18两种情况
		if ((code.length() != IDENTITYCODE_OLD)
				&& (code.length() != IDENTITYCODE_NEW)) {
			return false;
		}

		// 身份证号码必须为数字(18位的新身份证最后一位可以是x)
		Pattern pt = Pattern.compile("(^\\d{15}$)|(\\d{17}(?:\\d|x|X)$)");
		Matcher mt = pt.matcher(code);
		if (!mt.find()) {
			return false;
		}

		// 验证生日
		if (code.length() == IDENTITYCODE_OLD) {
			birthDay = "19" + code.substring(6, 12);
		} else {
			birthDay = code.substring(6, 14);
		}

		// 格式化日期
		try{
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
			Date date= sdf.parse(birthDay);
			if (date== null) {
				return false;
			}
		}catch (Exception e){
			return false;
		}

		// 最后一位校验码验证
		if (code.length() == IDENTITYCODE_NEW) {
			String tempId = code.substring(0,IDENTITYCODE_NEW - 1);
			int sum = 0;
			for (int i = 0; i < tempId.length(); i++)
			{
				int bye = tempId.charAt(i) - '0';
				sum += bye * coeff[i];
			}
			sum %= 11;
//			System.out.println("sum="+sum+"/end[sum]="+end[sum]);
//			System.out.println("code.substring="+code.substring(IDENTITYCODE_NEW-1,IDENTITYCODE_NEW));
			if(end[sum] != code.substring(IDENTITYCODE_NEW-1,IDENTITYCODE_NEW).charAt(0)){
				return false;
			}
		}
		return true;
	}

}
